package com.ccl.iot;import java.util.ArrayList;

import com.ccl.iot.privates.ListMap;
import com.ccl.iot.IOTInterface.IOTListener;
import com.ccl.iot.IOTObject.IOTListenObject;
import com.ccl.iot.object.IOTInfoWithValue;


public abstract class IOTInfoMonitor implements IOTListenObject {
	public interface IOTInfoListener extends IOTListener{
		public void onNewInfo(IOTInfoWithValue aInfo);
		public void onInfoChanged(IOTInfoWithValue aInfo);
		public void onInfoRemoved(IOTInfoWithValue aInfo);
	}
	
	private class NewInfo extends IOTInfoWithValue{
		NewInfo(IOTInfoWithValue aInfo){
			super(aInfo);
		}
	}
	
	private class ChangedInfo extends IOTInfoWithValue{
		ChangedInfo(IOTInfoWithValue aInfo){
			super(aInfo);
		}
	}
	
	private class RemoveInfo extends IOTInfoWithValue{
		RemoveInfo(IOTInfoWithValue aInfo){
			super(aInfo);
		}
	}
	
	private boolean iRetriving = false;
	private Object iSyncLock = new Object();
	private ArrayList<Object> iChangeLog = null;
	
	private ListMap<String, ArrayList<IOTInfoListener>> iInfoListeners = null;
	
	
	@Override
	public long getID(){
		return hashCode();
	}

	public boolean addInfoListener(String aName, IOTInfoListener aInfoListener){
		if (aName == null){
			aName = "";
		}
		
		if (aInfoListener != null){
			ArrayList<IOTInfoListener> tListeners = null;
			
			if (iInfoListeners == null){
				iInfoListeners = new ListMap<String, ArrayList<IOTInfoListener>>();
			}else{
				tListeners = iInfoListeners.getValue(aName);
			}
			
			if (tListeners == null){
				tListeners = new ArrayList<IOTInfoListener>();
				
				if (iInfoListeners.add(aName, tListeners) == false){
					return false;
				}
			}else{
				synchronized(tListeners){
					 if (tListeners.contains(aInfoListener)){
						 return false;
					 }
				}
			}

			return tListeners.add(aInfoListener);
		}
		
		return false;
	}
	
	public boolean addInfoListener(IOTInfoListener aInfoListener){
		return addInfoListener(null, aInfoListener);
	}
	
	public boolean removeInfoListener(String aName, IOTInfoListener aInfoListener){
		if (aInfoListener != null && iInfoListeners != null){
			ArrayList<IOTInfoListener> tListeners = null;
			
			if (aName == null){
				aName = "";
			}
			
			tListeners = iInfoListeners.getValue(aName);
			
			if (tListeners != null){
				synchronized(tListeners){
					return tListeners.remove(aInfoListener);
				}
			}
		}
		
		return false;
	}
	
	public boolean removeInfoListener(IOTInfoListener aInfoListener){
		if (aInfoListener != null && iInfoListeners != null){
			boolean tRet = false;
			ArrayList<IOTInfoListener> tListeners = null;
			
			for (int i = 0, tCount = iInfoListeners.size(); i < tCount; i++){
				if ((tListeners = iInfoListeners.getValueAt(i)) != null){
					synchronized(tListeners){
						tRet |= tListeners.remove(aInfoListener);
					}
				}
			}

			return tRet;
		}
		
		return false;
	}
	
	protected void onInfoChange(IOTInfoWithValue aInfo, boolean aNew){
		if (iRetriving == false){
			if (aInfo != null && iInfoListeners != null){
				String tNames[] = {"", aInfo.getName()};
				ArrayList<IOTInfoListener> tListeners = null;
				IOTInfoListener tListener;
				
				for (int i = 0; i < 2; i++){
					if ((tListeners = iInfoListeners.getValue(tNames[i])) != null){
						synchronized(tListeners){
							for (int j = 0, tCount = tListeners.size(); j < tCount; j++){
								if ((tListener = tListeners.get(j)) != null){
									if (aNew){
										tListener.onNewInfo(aInfo);
									}else{
										tListener.onInfoChanged(aInfo);
									}
								}
							}
						}
					}
				}
			}
		}else{
			if (iChangeLog == null){
				iChangeLog = new ArrayList<Object>();
			}
			
			if (aNew){
				iChangeLog.add(new NewInfo(aInfo));
			}else{
				iChangeLog.add(new ChangedInfo(aInfo));
			}
		}
	}
	
	protected void onInfoRemoved(IOTInfoWithValue aInfo){
		if (iRetriving == false){
			if (aInfo != null && iInfoListeners != null){
				String tNames[] = {"", aInfo.getName()};
				ArrayList<IOTInfoListener> tListeners = null;
				IOTInfoListener tListener;
				
				for (int i = 0; i < 2; i++){
					if ((tListeners = iInfoListeners.getValue(tNames[i])) != null){
						synchronized(tListeners){
							for (int j = 0, tCount = tListeners.size(); j < tCount; j++){
								if ((tListener = tListeners.get(j)) != null){
									tListener.onInfoRemoved(aInfo);
								}
							}
						}
					}
				}
			}
		}else{
			if (iChangeLog == null){
				iChangeLog = new ArrayList<Object>();
			}
			
			iChangeLog.add(new RemoveInfo(aInfo));
		}
	}
	
	protected void onInfoRetriveStart(){
		synchronized(iSyncLock){
			iRetriving = true;
		}
	}
	
	protected void onInfoRetriveStop(){
		synchronized(iSyncLock){
			iRetriving = false;
			
			if (iChangeLog != null){
				int tCount1 = iChangeLog.size();
				
				if (tCount1 > 0){
					if (iInfoListeners != null){
						int tCount2 = iInfoListeners.size();
						
						if (tCount2 > 0){
							for (int i = 0; i < tCount2; i++){
								ArrayList<IOTInfoListener> tListeners;
								
								if ((tListeners = iInfoListeners.getValueAt(i)) != null){
									String tMatch = iInfoListeners.getKeyAt(i);
									
									if (tMatch != null){
										for (int j = 0, tCount3 = tListeners.size(); j < tCount3; j++){
											IOTInfoListener tListener;
											
											if ((tListener = tListeners.get(j)) != null){
												for (int k = 0; k < tCount1; k++){
													Object tChange = iChangeLog.get(k);
													
													if (tChange != null){
														if (tChange instanceof NewInfo){
															if (tMatch.length() == 0 || tMatch.equals(((NewInfo) tChange).getName())){
																tListener.onNewInfo((IOTInfoWithValue) tChange);
															}
														}else if (tChange instanceof ChangedInfo){
															if (tMatch.length() == 0 || tMatch.equals(((ChangedInfo) tChange).getName())){
																tListener.onInfoChanged((IOTInfoWithValue) tChange);
															}
														}else if (tChange instanceof RemoveInfo){
															if (tMatch.length() == 0 || tMatch.equals(tChange)){
																tListener.onInfoRemoved((RemoveInfo) tChange);
															}
														}
													}
												}
											}
										}
									}
								}
							}
							
							if(mInfoChangedDone != null){
								mInfoChangedDone.onInfoChangedDone();
							}
						}
					}
					
					iChangeLog.clear();
				}
			}
		}
	}
	
	//=================modify start========================
	public interface OnInfoChangedDoneListener{
		public void onInfoChangedDone();
	}
	private OnInfoChangedDoneListener mInfoChangedDone;
	public void setOnInfoChangedDoneListener(OnInfoChangedDoneListener listener){
		mInfoChangedDone = listener;
	}
	//=================modify end========================
}
